﻿using System;
using System.Collections.Generic;
using System.Windows.Input;
#if SILVERLIGHT
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
#endif

namespace Microsoft.PlayerFramework
{
    /// <summary>
    /// Behavior to support binding commands to a Selector (or ComboBox) control
    /// </summary>
    public static class SelectorBehavior
    {
        /// <summary>
        /// Identifies the Command dependency property.
        /// </summary>
        public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(SelectorBehavior), new PropertyMetadata(null, Attach));

        /// <summary>
        /// Sets the command to a Selector control.
        /// </summary>
        /// <param name="obj">The dependency object to attach the command to. This should always be a ComboBox</param>
        /// <param name="propertyValue">The command to attach.</param>
        public static void SetCommand(DependencyObject obj, ICommand propertyValue)
        {
            if (obj == null) throw new ArgumentNullException("obj");
            obj.SetValue(CommandProperty, propertyValue);
        }

        /// <summary>
        /// Gets the command associated with the Selector control.
        /// </summary>
        /// <param name="obj">The Selector control to get the associated command for.</param>
        /// <returns>The command associated with the selector control.</returns>
        public static ICommand GetCommand(DependencyObject obj)
        {
            if (obj == null) throw new ArgumentNullException("obj");
            return obj.GetValue(CommandProperty) as ICommand;
        }

        static Dictionary<Selector, Action> DetachActions = new Dictionary<Selector, Action>();

        static void Attach(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var selector = d as Selector;
            if (selector != null)
            {
                var oldValue = e.OldValue as ICommand;
                var newValue = e.NewValue as ICommand;
                if (oldValue != null) DetachCommand(selector);
                if (newValue != null) AttachCommand(selector, newValue);
            }
        }

        static void AttachCommand(Selector selector, ICommand command)
        {
            selector.IsEnabled = command.CanExecute(null);
            EventHandler CanExecuteChangedEventHandler = (s, e) => selector.IsEnabled = command.CanExecute(null);
            command.CanExecuteChanged += CanExecuteChangedEventHandler;
            SelectionChangedEventHandler SelectionChangedEventHandler = (s, e) =>
            {
                if (command.CanExecute(null))
                {
                    command.Execute(selector.SelectedIndex);
                }
            };
            selector.SelectionChanged += SelectionChangedEventHandler;

            DetachActions.Add(selector, () =>
            {
                command.CanExecuteChanged -= CanExecuteChangedEventHandler;
                selector.SelectionChanged -= SelectionChangedEventHandler;
            });
        }

        static void DetachCommand(Selector selector)
        {
            var action = DetachActions[selector];
            action();
            DetachActions.Remove(selector);
        }

    }
}
